package com.magold.logic.pipe;

import java.util.HashMap;
import java.util.Map;

import org.andengine.entity.IEntity;
import org.andengine.entity.modifier.IEntityModifier.IEntityModifierListener;
import org.andengine.entity.modifier.SequenceEntityModifier.ISubSequenceShapeModifierListener;
import org.andengine.entity.shape.IAreaShape;
import org.andengine.util.modifier.IModifier;

import android.util.Log;

import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.magold.logic.ISpriteLogic;
import com.magold.logic.LogicComponentFinder;
import com.magold.physics.MagoldPhysicsConnector;

/**
 * Listen for SequenceModifier.
 * 
 * @author Eternity
 *
 */
public class PipeMoveListener implements ISubSequenceShapeModifierListener, IEntityModifierListener {
	private static final float VELOCITY = 10;
			
	private HaloPool mHaloPool;
	private Map<ISpriteLogic, Halo> mTransferringItems;
	
	public PipeMoveListener(HaloPool pPool) {
		mHaloPool = pPool;
		mTransferringItems = new HashMap<ISpriteLogic, Halo>();
	}

	public Halo getBindingHalo(ISpriteLogic pLogic) {
		return mTransferringItems.get(pLogic);
	}
	
	@Override
	public void onSubSequenceStarted(IModifier<IEntity> pModifier, IEntity pItem, int pIndex) {
		IAreaShape shape = (IAreaShape) pItem;
		switch (pIndex) {
		case PipeMoveModifier.SHRINK_INDEX:
			dispatchHalo(shape);
			disablePhysics(shape);
			break;
		case PipeMoveModifier.TRANSFER_INDEX:
			showHalo(shape);
			break;
		}
	}

	@Override
	public void onSubSequenceFinished(IModifier<IEntity> pModifier, IEntity pItem, int pIndex) {
		IAreaShape shape = (IAreaShape) pItem;
		switch (pIndex) {
		case PipeMoveModifier.MAGNIFY_INDEX:
			break;
		case PipeMoveModifier.TRANSFER_INDEX:
			hideHalo(shape);
			centerCoord(shape);
			break;
		}
	}

	@Override
	public void onModifierStarted(IModifier<IEntity> pModifier, IEntity pItem) {
	}

	@Override
	public void onModifierFinished(IModifier<IEntity> pModifier, IEntity pItem) {
		PipeMoveModifier modifier = (PipeMoveModifier) pModifier;
		IAreaShape shape = (IAreaShape) pItem;
		
		enablePhysics(shape, modifier.computeOutDirection());
	}

	private void showHalo(IAreaShape pShape) {
		Halo halo = mTransferringItems.get(pShape.getUserData());
		
		if (halo == null) {
			Log.e("PIPEMOVELISTENER", "NULLLLLLLLLLLL.");
			dispatchHalo(pShape);
			disablePhysics(pShape);
			halo = mTransferringItems.get(pShape.getUserData());
		}
		
		halo.setFollowingShape(pShape);
		halo.appear();
		halo.visited = true;
	}
	
	private void hideHalo(IAreaShape pShape) {
		Halo halo = mTransferringItems.get(pShape.getUserData());
		halo.disappear();
	}
	
	private void centerCoord(IAreaShape pShape) {
		float x = pShape.getX(), y = pShape.getY();
		float w = pShape.getWidth(), h = pShape.getHeight();
		pShape.setPosition(x - w/2, y - h/2);
	}

	private void disablePhysics(IAreaShape pShape) {
		MagoldPhysicsConnector connector = LogicComponentFinder.findConnector(pShape);
		if (connector != null) {
			connector.setPhysicsEnabled(false);
		}
	}
	
	private void enablePhysics(IAreaShape pShape, Vector2 pDirection) {
		MagoldPhysicsConnector connector = LogicComponentFinder.findConnector(pShape);
		if (connector != null) {
			connector.updateBodyToShape();
			
			connector.setPhysicsEnabled(true);
			Body body = connector.getBody();
			body.setLinearVelocity(0, 0);
			
			Vector2 impulse = pDirection.mul(body.getMass()*VELOCITY);
			body.applyLinearImpulse(impulse, body.getWorldCenter());
		}
	}

	private void dispatchHalo(IAreaShape pShape) {
		Halo halo = mHaloPool.obtainPoolItem();
		
		mTransferringItems.put((ISpriteLogic) pShape.getUserData(), halo);
	}
	
	public void recycleHalo(ISpriteLogic pKey) {
		Halo bindingHalo = mTransferringItems.remove(pKey);
		
		// XXX BUG
		if (!bindingHalo.visited) return;
		
		bindingHalo.visited = false;
		
		if (bindingHalo != null) {
			mHaloPool.recyclePoolItem(bindingHalo);
		}
	}
	
}
